package com.ciklum.robotester;

import com.gooddies.exceptions.ErrorMessageException;

import java.awt.*;
import java.awt.event.InputEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.*;

public class RobotesterImpl implements IRobotesterApi {
    private final Robot robot;
    private final ImageMatcher im;
    private final long defaultTimeout;
    private ExecutorService executorService = Executors.newSingleThreadExecutor();

    public RobotesterImpl(long defaultTimeout)  {
        try {
            robot = new Robot();
        } catch (AWTException e) {
            throw new ErrorMessageException("",e);
        }
        im = new ImageMatcher(robot);
        if(defaultTimeout<100){
            throw new IllegalArgumentException("Invalid timeout. Timeout must be over 100ms.");
        }
        this.defaultTimeout = defaultTimeout;
    }

    @Override
    public Point findControl(final File file, long timeout) throws TimeoutException {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream(file));
        } catch (IOException e) {
            throw new ErrorMessageException("",e);
        }
        final File img = new File(properties.getProperty("imagePath"));
        Point point = findImgAndClick(img, timeout);
        point.x = point.x +Integer.parseInt(properties.getProperty("dx"));
        point.y = point.y + Integer.parseInt(properties.getProperty("dy"));
        return point;
    }

    private Point findImgAndClick(final File file,long timeout) throws TimeoutException {
        Point point = null;

        Future<Point> future = null;
        try {
            future= executorService.submit(new Callable<Point>() {
                @Override
                public Point call() throws Exception {
                    while (true) {
                        Point p = im.find(file);
                        if (p != null) {
                            return p;
                        } else {
                            Thread.currentThread().sleep(90);
                        }
                    }
                }
            });
            point = future.get(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            throw new RuntimeException(e.getCause());
        } catch (TimeoutException e) {
            future.cancel(true);
            throw e;
        }
        return point;
    }
    @Override
    public boolean findControlAndClick(File file, long timeout) throws TimeoutException {
        Point point = findControl(file, timeout);
        click(point.x,point.y,MouseButton.L_BUTTON);
        return true;
    }

    @Override
    public boolean findControlAndClick(File file, MouseButton mouseButton, long timeout) throws TimeoutException {
        Point point = findControl(file, timeout);
        click(point.x,point.y,mouseButton);
        return true;
    }

    @Override
    public Point findControl(File file) throws TimeoutException {
        return findControl(file, defaultTimeout);
    }

    @Override
    public boolean findControlAndClick(File file) throws TimeoutException {
        Point point=findControl(file, defaultTimeout);
        click(point.x,point.y,MouseButton.L_BUTTON);
        return true;

    }

    @Override
    public void click(int x, int y, MouseButton mouseButton) {
        move(x, y);
        int btn = -1;
        switch (mouseButton) {
            case L_BUTTON:
                btn = InputEvent.BUTTON1_MASK;
                break;
            case R_BUTTON:
                btn = InputEvent.BUTTON3_MASK;
                break;
            case C_BUTTON:
                btn = InputEvent.BUTTON3_DOWN_MASK;
                break;
        }
        robot.mousePress(btn);
        robot.mouseRelease(btn);
    }

    @Override
    public void move(int x, int y) {
        robot.mouseMove(x, y);
    }

    @Override
    public void keyPress(int i) {
        robot.keyPress(i);

    }

    @Override
    public void keyPress(char i) {
        robot.keyPress(i);

    }

    @Override
    public void keyType(char i) {
        robot.keyPress(i);
        robot.keyRelease(i);
    }

    @Override
    public void typeString(String s) {
        if(s==null){
            s = "";
        }
        char[] arr = s.toCharArray();
        for (char c:arr){
            keyType(c);
        }

    }

    @Override
    public boolean existsOnScreen(File file) {
        return null==im.find(file);
    }

    @Override
    public Point waitForImage(File file, long timeout) throws TimeoutException {

        return null;
    }

    @Override
    public void waitForImageDisappear(File file, long timeout) throws TimeoutException {

    }

    @Override
    public void setThroughput(double throughput) {
        im.setThroughput(throughput);
    }


    public static void main(String[] args) throws AWTException, TimeoutException, IOException {
        RobotesterImpl api = new RobotesterImpl(10000);
        Point p = api.findControl(new File("D://2873899.img"));
        api.click(p.x, p.y, MouseButton.R_BUTTON);

//        api.click(0,0,MouseButton.R_BUTTON);


    }
}
